// Copyright (C) 2010  Joan Puigcerver Perez, <joapuipe@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef __PEOPLE_HPP__
#define __PEOPLE_HPP__

#include <map>
#include <list>
#include <vector>
#include <string>

#include <Person.hpp>
#include <MapKey.hpp>
#include <MapNode.hpp>
#include <LogUtils.hpp>
#include <StringTrie.hpp>

/** File where people info is stored. */
#define PEOPLE_XML "xml/people.xml"
/** XML Schema used to check the format of PEOPLE_XML. */
#define PEOPLE_XSD "xml/people.xsd"

class Database;

/**
 * \class People
 *
 * This class is used to manage the set of persons in the database.
 * Each Person node is created dinamically and its address is stored
 * in a vector of pointers. In addition, it is also created a new node
 * in a map. This map is used to find the association name-person in O(log n).
 * Movies class has a similar behaviour.
 * \see Movies
 */
class People {
public:
  typedef Trie<Person>::ApproximateLookupItem ApproximateLookupItem;

private:
  std::ostream& logfile;
  ost::Mutex&  log_mutex;

  Trie<Person> people;
  std::vector<Person*> people_container;
  size_t num_persons;

  /**
   * Function used create and to add a new Person into de database. 
   * This function can't be used publicly. Use load() instead.
   * @see load
   */  
  Person * add_person(const std::string& name);
  /** 
   * Function used to add a new aka name to a given Person (as a pointer). 
   * This function can't be used publicly. Use load() instead.
   * @see load
   */
  void add_aka(const std::string& aka, Person* person);

public:

  /** 
   * Constructor.
   *
   * @param logf Output stream used to print log messages.
   * @param logm Mutex to control the access to logf.
   */
  People(std::ostream& logf = std::cout, ost::Mutex& logm = LOGmutex);

  /**
   * Destructor. Deletes all the created Person objects.
   */
  ~People();

  /**
   * This method is used to load a people XML file into a desired database.
   * It was necessary to pass a Database object because the links between
   * movies and persons are created at this time.
   */
  bool load(Database * database);

  //const Person * exact_search(const std::string& name) const;

  /**
   * This function basically performs a binary search within among the persons in the database.
   * If the exact name was found, then the first argument returned is true. Otherwise, false is returned.
   * If the exact name was found and it is the main name for some person, then just this person is returned
   * in the list. If the name is not the main name for any person, all the persons with that aka name are
   * returned.
   * If the exact name was not found, a list of persons with similar main names or aka names are returned.
   */
  typedef std::pair< bool,std::list< std::pair<const Person*, std::string> > > Tsearch;
  Tsearch search(const std::string& name) const;

  /** This returns the number of persons in the database. */
  size_t size(void) const;

  void print () const {
    people.print();
  }
 
  friend class SAXPeopleHandler;
  friend class Database;
};

#endif
